#include <iostream>
#include <stdarg.h>
using namespace std;

class EquationSolver
{
public:
    EquationSolver()
        : have(false){};

    virtual bool solve() = 0;
    double ans()
    {
        return root;
    }
    void set_M(int in)
    {
        M = in;
        return;
    }

protected:
    double root;
    double epsilon;
    int M;
    bool have;
    double (*fun)(double);
    int sgn(double x)
    {
        if (x > 0)
            return 1;
        else if (x < 0)
            return -1;
        else
            return 0;
    }
};

class biesection : virtual public EquationSolver
{
public:
    biesection() : EquationSolver() {}
    biesection(double a_in,
               double b_in,
               double (*f)(double),
               double epsilon_in = 0.01)
    {
        a = a_in,
        b = b_in,
        M = 60,
        epsilon = epsilon_in,
        fun = f,
        have = true;
    };
    void operator()(double a_in,
                    double b_in,
                    double (*f)(double),
                    double epsilon_in = 0.01) { a = a_in,
                                                b = b_in,
                                                M = 60,
                                                epsilon = epsilon_in,
                                                fun = f,
                                                have = true; };

    bool solve()
    {

        if (!have)
        {
            return false;
        }

        double h = b - a;
        double w;
        double u = fun(a);

        for (int i = 0; i < M; i++)
        {
            h = h / 2;
            root = a + h;
            if (abs(h) < 1e-6)
            {
                break;
            }
            w = fun(root);
            if (abs(w) < epsilon)
            {
                return true;
                break;
            }
            else if (sgn(w) == sgn(u))
            {
                a = root;
            }
        }

        return false;
    };

protected:
    double a;
    double b;
};

class Newton : virtual public EquationSolver
{
public:
    Newton()
        : EquationSolver(){};
    Newton(double (*f)(double), double (*f_)(double), double x_0, int M_in = 40, double epsilon_in = 1e-6)
    {
        M = 40,
        epsilon = epsilon_in,
        root = x_0;
        diff = f_,
        fun = f,
        have = true;
    }

    void operator()(
        double (*f)(double),
        double (*f_)(double),
        double x_0 = 0,
        double epsilon_in = 1e-6)
    {
        M = 40,
        epsilon = epsilon_in,
        diff = f_,
        root = x_0;
        fun = f,
        have = true;
    }

    double (*diff)(double);

    bool solve()
    {

        if (!have)
        {
            return false;
        }

        double u;
        for (int i = 0; i < M; i++)
        {
            u = fun(root);
            if (abs(u) < epsilon)
            {
                return true;
            }
            root = root - u / diff(root);
        }
        return false;
    }

protected:
    double x;
};

class secant : public EquationSolver
{
public:
    secant() : EquationSolver(){};
    secant(double (*f)(double), double x_0 = 0, double x_1 = -0.3, double epsilon_in = 0.001)
    {
        fun = f, root = x_1, pre = x_0, epsilon = epsilon_in,M=40, have = true;
    }
    void operator()(
        double (*f)(double),
        double x_0 = 0,
        double x_1 = -0.3,
        double epsilon_in = 0.001)
    {
        fun = f, root = x_1, pre = x_0, epsilon = epsilon_in,M=40, have = true;
    }

    bool solve()
    {

        double u(fun(root)), v(fun(pre));
        double s;
        for (int i = 0; i < M; i++)
        {
            s = (root - pre) / (u - v);
            pre = root;
            v = u;
            root = root - u * s;
            if (abs(root - pre) < epsilon*1e-3)
            {
                return false;
            }
            u = fun(root);
            if (abs(u) < epsilon)
            {
                return true;
            }
            
        }
        return false;
    }

protected:
    double pre;
};
